﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TestByWire.AttributeHandlers;
using Microsoft.Practices.Unity;

namespace TestByWire
{
	using System.Reflection;

	internal class UseFakeLateBoundInteraction : IContainerInteraction
	{
		public UseFakeLateBoundInteraction(string registrationName, object fakeInstance)
		{
			if (registrationName == null)
			{
				throw new ArgumentNullException("registrationName");
			}
			if (fakeInstance == null)
			{
				throw new ArgumentNullException("fakeInstance");
			}

			RegistrationName = registrationName;
			FakeInstance = fakeInstance;
			RegistrationType = fakeInstance.GetType();
		}

		public Type RegistrationType { get; private set; }
		public string RegistrationName { get; private set; }

		public object FakeInstance { get; set; }

		public void Execute(IBuildContext buildContext)
		{
			if (buildContext.TestTarget == null)
			{
				return;
			}

			Type testTargetType = buildContext.TestTarget.GetType();
			FieldInfo fieldInfo = GetFieldInfo(testTargetType, RegistrationName);
			if (fieldInfo == null)
			{
				throw new InvalidOperationException(string.Format("Field: {0}, does not exist on Test Target: {1}", RegistrationName, testTargetType));
			}

			fieldInfo.SetValue(buildContext.TestTarget, FakeInstance);
		}

		private static FieldInfo GetFieldInfo(Type targetInstanceType, string fieldName)
		{
			var fieldInfo = targetInstanceType.GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic);
			if (fieldInfo == null && targetInstanceType.BaseType != typeof(Object))
				return GetFieldInfo(targetInstanceType.BaseType, fieldName);

			return fieldInfo;
		}
	}
}
